package cn.edu.tju.elm.service;

import cn.edu.tju.core.model.*;
import cn.edu.tju.elm.mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * 钱包服务
 */
@Service
public class WalletService {

    @Autowired
    private WalletMapper walletMapper;
    
    @Autowired
    private WalletTransactionMapper transactionMapper;
    
    @Autowired
    private WalletRuleMapper walletRuleMapper;
    
    @Autowired(required = false)
    private OverdraftRecordMapper overdraftRecordMapper;

    /**
     * 创建钱包
     */
    @Transactional(rollbackFor = Exception.class)
    public VirtualWallet createWallet(Integer userId, Boolean isVip) {
        VirtualWallet existing = walletMapper.selectByUserId(userId);
        if (existing != null) {
            throw new IllegalStateException("用户已有钱包");
        }
        
        VirtualWallet wallet = new VirtualWallet();
        wallet.setUserId(userId);
        wallet.setIsVip(isVip != null && isVip ? 1 : 0);
        
        walletMapper.insert(wallet);
        return wallet;
    }

    /**
     * 充值
     */
    @Transactional(rollbackFor = Exception.class)
    public Transaction recharge(Integer userId, BigDecimal amount) {
        VirtualWallet wallet = getWalletByUserId(userId);
        BigDecimal balanceBefore = wallet.getBalance();
        
        // 计算充值奖励
        BigDecimal bonus = calculateRechargeBonus(amount);
        
        // 调用Domain模型的业务方法
        wallet.recharge(amount, bonus);
        
        // 乐观锁更新
        int updated = walletMapper.updateWithOptimisticLock(wallet);
        if (updated == 0) {
            throw new RuntimeException("钱包更新失败，请重试");
        }
        
        // 记录交易流水
        Transaction transaction = createTransaction(
            wallet, "RECHARGE", amount, balanceBefore, wallet.getBalance(),
            "充值" + amount + (bonus.compareTo(BigDecimal.ZERO) > 0 ? "，赠送" + bonus : "")
        );
        transactionMapper.insert(transaction);
        
        return transaction;
    }

    /**
     * 提现
     */
    @Transactional(rollbackFor = Exception.class)
    public Transaction withdraw(Integer userId, BigDecimal amount) {
        VirtualWallet wallet = getWalletByUserId(userId);
        BigDecimal balanceBefore = wallet.getBalance();
        
        // 计算手续费和扣除的赠送金额
        BigDecimal fee = calculateWithdrawFee(amount);
        BigDecimal deductBonus = calculateDeductBonus(wallet, amount);
        
        // 调用Domain模型的业务方法
        wallet.withdraw(amount, fee, deductBonus);
        
        // 乐观锁更新
        int updated = walletMapper.updateWithOptimisticLock(wallet);
        if (updated == 0) {
            throw new RuntimeException("钱包更新失败，请重试");
        }
        
        // 记录交易流水
        String desc = "提现" + amount + "，手续费" + fee;
        if (deductBonus.compareTo(BigDecimal.ZERO) > 0) {
            desc += "，扣除赠送金额" + deductBonus;
        }
        Transaction transaction = createTransaction(
            wallet, "WITHDRAW", amount.add(fee).negate(), balanceBefore, wallet.getBalance(), desc
        );
        transactionMapper.insert(transaction);
        
        return transaction;
    }

    /**
     * 支付（用户间转账）
     */
    @Transactional(rollbackFor = Exception.class)
    public void payment(Integer fromUserId, Integer toUserId, BigDecimal amount, Long orderId) {
        // 获取双方钱包
        VirtualWallet fromWallet = getWalletByUserId(fromUserId);
        VirtualWallet toWallet = getWalletByUserId(toUserId);
        
        BigDecimal fromBalanceBefore = fromWallet.getBalance();
        BigDecimal toBalanceBefore = toWallet.getBalance();
        
        // 调用Domain模型的业务方法
        fromWallet.pay(amount);
        toWallet.receive(amount);
        
        // 乐观锁更新双方钱包
        int updated1 = walletMapper.updateWithOptimisticLock(fromWallet);
        int updated2 = walletMapper.updateWithOptimisticLock(toWallet);
        
        if (updated1 == 0 || updated2 == 0) {
            throw new RuntimeException("支付失败，请重试");
        }
        
        // 记录付款方流水
        Transaction payTransaction = createTransaction(
            fromWallet, "PAYMENT", amount.negate(), fromBalanceBefore, fromWallet.getBalance(),
            "支付给用户" + toUserId
        );
        payTransaction.setRelatedWalletId(toWallet.getId());
        payTransaction.setOrderId(orderId);
        transactionMapper.insert(payTransaction);
        
        // 记录收款方流水
        Transaction receiveTransaction = createTransaction(
            toWallet, "RECEIVE", amount, toBalanceBefore, toWallet.getBalance(),
            "收款自用户" + fromUserId
        );
        receiveTransaction.setRelatedWalletId(fromWallet.getId());
        receiveTransaction.setRelatedTransactionId(payTransaction.getId());
        receiveTransaction.setOrderId(orderId);
        transactionMapper.insert(receiveTransaction);
    }

    /**
     * 冻结金额
     */
    @Transactional(rollbackFor = Exception.class)
    public Transaction freezeAmount(Integer userId, BigDecimal amount, Long orderId) {
        VirtualWallet wallet = getWalletByUserId(userId);
        BigDecimal balanceBefore = wallet.getBalance();
        
        // 调用Domain模型的业务方法
        wallet.freeze(amount);
        
        // 乐观锁更新
        int updated = walletMapper.updateWithOptimisticLock(wallet);
        if (updated == 0) {
            throw new RuntimeException("冻结失败，请重试");
        }
        
        // 记录交易流水
        Transaction transaction = createTransaction(
            wallet, "FREEZE", BigDecimal.ZERO, balanceBefore, wallet.getBalance(),
            "冻结金额" + amount
        );
        transaction.setOrderId(orderId);
        transactionMapper.insert(transaction);
        
        return transaction;
    }

    /**
     * 解冻金额
     */
    @Transactional(rollbackFor = Exception.class)
    public Transaction unfreezeAmount(Integer userId, BigDecimal amount, Long orderId) {
        VirtualWallet wallet = getWalletByUserId(userId);
        BigDecimal balanceBefore = wallet.getBalance();
        
        // 调用Domain模型的业务方法
        wallet.unfreeze(amount);
        
        // 乐观锁更新
        int updated = walletMapper.updateWithOptimisticLock(wallet);
        if (updated == 0) {
            throw new RuntimeException("解冻失败，请重试");
        }
        
        // 记录交易流水
        Transaction transaction = createTransaction(
            wallet, "UNFREEZE", BigDecimal.ZERO, balanceBefore, wallet.getBalance(),
            "解冻金额" + amount
        );
        transaction.setOrderId(orderId);
        transactionMapper.insert(transaction);
        
        return transaction;
    }

    /**
     * 扣除冻结金额（订单确认收货时调用）
     */
    @Transactional(rollbackFor = Exception.class)
    public void deductFrozenAmount(Integer userId, BigDecimal amount, Long orderId) {
        VirtualWallet wallet = getWalletByUserId(userId);
        BigDecimal balanceBefore = wallet.getBalance();
        
        // 调用Domain模型的业务方法
        wallet.deductFrozen(amount);
        
        // 乐观锁更新
        int updated = walletMapper.updateWithOptimisticLock(wallet);
        if (updated == 0) {
            throw new RuntimeException("扣除冻结金额失败，请重试");
        }
        
        // 记录交易流水
        Transaction transaction = createTransaction(
            wallet, "DEDUCT_FROZEN", amount.negate(), balanceBefore, wallet.getBalance(),
            "扣除冻结金额" + amount
        );
        transaction.setOrderId(orderId);
        transactionMapper.insert(transaction);
    }

    /**
     * 查询余额
     */
    public VirtualWallet getBalance(Integer userId) {
        return getWalletByUserId(userId);
    }

    /**
     * 查询交易流水
     */
    public List<Transaction> getTransactions(Integer userId, Integer page, Integer pageSize) {
        VirtualWallet wallet = getWalletByUserId(userId);
        int offset = (page - 1) * pageSize;
        return transactionMapper.selectByWalletId(wallet.getId(), offset, pageSize);
    }

    /**
     * 设置VIP透支额度
     */
    @Transactional(rollbackFor = Exception.class)
public void setCreditLimit(Integer userId, BigDecimal creditLimit) {
    VirtualWallet wallet = getWalletByUserId(userId);
    
    if (wallet.getIsVip() != 1) {
        throw new IllegalStateException("仅VIP用户可设置透支额度");
    }
    
    wallet.setCreditLimit(creditLimit);
    
    // 使用乐观锁更新，与其他方法保持一致
    int updated = walletMapper.updateWithOptimisticLock(wallet);
    if (updated == 0) {
        throw new RuntimeException("设置透支额度失败，请重试");
    }
}

    /**
     * 计算透支利息（定时任务调用）
     */
    @Transactional(rollbackFor = Exception.class)
    public void calculateOverdraftInterest() {
        if (overdraftRecordMapper == null) {
            return; 
        }
        
        List<OverdraftRecord> overdueRecords = overdraftRecordMapper.selectOverdueRecords();
        
        for (OverdraftRecord record : overdueRecords) {
            long days = (System.currentTimeMillis() - record.getOverdraftDate().getTime()) / (1000 * 60 * 60 * 24);
            BigDecimal interest = record.getOverdraftAmount()
                .multiply(record.getInterestRate())
                .multiply(BigDecimal.valueOf(days))
                .setScale(2, RoundingMode.HALF_UP);
            
            record.setInterestAmount(interest);
            record.setStatus("OVERDUE");
            overdraftRecordMapper.updateById(record);
            
            VirtualWallet wallet = walletMapper.selectById(record.getWalletId());
            Transaction transaction = createTransaction(
                wallet, "INTEREST", interest.negate(), wallet.getBalance(), wallet.getBalance(),
                "透支利息"
            );
            transactionMapper.insert(transaction);
        }
    }

    // ========== 私有方法 ==========

    private VirtualWallet getWalletByUserId(Integer userId) {
        VirtualWallet wallet = walletMapper.selectByUserId(userId);
        if (wallet == null) {
            throw new IllegalArgumentException("钱包不存在");
        }
        return wallet;
    }

    /**
     * 计算充值奖励
     */
    private BigDecimal calculateRechargeBonus(BigDecimal amount) {
        try {
            List<WalletRule> rules = walletRuleMapper.selectActiveRulesByType("RECHARGE_BONUS");
            
            for (WalletRule rule : rules) {
                // 检查金额是否在规则范围内
                if (amount.compareTo(rule.getMinAmount()) >= 0 && 
                    (rule.getMaxAmount() == null || amount.compareTo(rule.getMaxAmount()) <= 0)) {
                    
                    // 计算奖励：优先使用固定奖励，其次使用比例奖励
                    if (rule.getFixedBonus() != null && rule.getFixedBonus().compareTo(BigDecimal.ZERO) > 0) {
                        return rule.getFixedBonus();
                    } else if (rule.getBonusRate() != null && rule.getBonusRate().compareTo(BigDecimal.ZERO) > 0) {
                        return amount.multiply(rule.getBonusRate())
                                    .setScale(2, RoundingMode.HALF_UP);
                    }
                }
            }
        } catch (Exception e) {
            // 规则计算失败，返回0奖励
            e.printStackTrace();
        }
        
        return BigDecimal.ZERO;
    }

    /**
     * 计算提现手续费
     */
    private BigDecimal calculateWithdrawFee(BigDecimal amount) {
        try {
            List<WalletRule> rules = walletRuleMapper.selectActiveRulesByType("WITHDRAW_FEE");
            
            for (WalletRule rule : rules) {
                if (amount.compareTo(rule.getMinAmount()) >= 0 && 
                    (rule.getMaxAmount() == null || amount.compareTo(rule.getMaxAmount()) <= 0)) {
                    
                    // 计算手续费：优先使用固定费用，其次使用比例费用
                    if (rule.getFixedFee() != null && rule.getFixedFee().compareTo(BigDecimal.ZERO) > 0) {
                        return rule.getFixedFee();
                    } else if (rule.getFeeRate() != null && rule.getFeeRate().compareTo(BigDecimal.ZERO) > 0) {
                        return amount.multiply(rule.getFeeRate())
                                    .setScale(2, RoundingMode.HALF_UP);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return BigDecimal.ZERO;
    }

    /**
     * 计算提现时应扣除的赠送金额
     * 按照提现金额占总资产的比例扣除
     */
    private BigDecimal calculateDeductBonus(VirtualWallet wallet, BigDecimal amount) {
        BigDecimal totalAssets = wallet.getTotalAssets();
        
        if (totalAssets.compareTo(BigDecimal.ZERO) <= 0 || 
            wallet.getBonusAmount().compareTo(BigDecimal.ZERO) <= 0) {
            return BigDecimal.ZERO;
        }
        
        // 提现金额占总资产的比例
        BigDecimal ratio = amount.divide(totalAssets, 4, RoundingMode.HALF_UP);
        
        // 按比例扣除赠送金额
        BigDecimal deduct = wallet.getBonusAmount().multiply(ratio)
                                  .setScale(2, RoundingMode.HALF_UP);
        
        // 不能超过实际赠送金额
        return deduct.min(wallet.getBonusAmount());
    }

    /**
     * 创建交易记录
     */
    private Transaction createTransaction(VirtualWallet wallet, String type, 
                                        BigDecimal amount, BigDecimal balanceBefore, 
                                        BigDecimal balanceAfter, String description) {
        Transaction transaction = new Transaction();
        transaction.setTransactionNo(generateTransactionNo());
        transaction.setWalletId(wallet.getId());
        transaction.setUserId(wallet.getUserId());
        transaction.setType(type);
        transaction.setAmount(amount);
        transaction.setBalanceBefore(balanceBefore);
        transaction.setBalanceAfter(balanceAfter);
        transaction.setDescription(description);
        transaction.setCreatedAt(Timestamp.valueOf(LocalDateTime.now()));
        return transaction;
    }

    /**
     * 生成交易号
     */
    private String generateTransactionNo() {
        return "T" + System.currentTimeMillis() + 
               UUID.randomUUID().toString().replace("-", "").substring(0, 8).toUpperCase();
    }

    /** 获取用户的冻结交易记录*/
    public List<Transaction> getFrozenTransactions(Integer userId) {
    VirtualWallet wallet = getWalletByUserId(userId);
    return transactionMapper.selectByWalletIdAndType(wallet.getId(), "FREEZE");
}
    /**
 * 根据交易ID获取交易详情（会验证用户权限）
 */
    public Transaction getTransactionById(Integer userId, Long transactionId) {
    // 先获取用户钱包
    VirtualWallet wallet = getWalletByUserId(userId);
    
    // 根据交易ID查询交易记录
    Transaction transaction = transactionMapper.selectById(transactionId);
    
    if (transaction == null) {
        throw new IllegalArgumentException("交易记录不存在");
    }
    
    // 验证该交易是否属于当前用户
    if (!transaction.getWalletId().equals(wallet.getId())) {
        throw new SecurityException("无权查看该交易记录");
    }
    
    return transaction;
}
}